package com.ctg.sysmgr.sso.client.control.filter;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;

import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.jasig.cas.client.util.AbstractCasFilter;
import org.jasig.cas.client.util.CommonUtils;

import com.ctg.sysmgr.sso.client.control.util.HttpClientHelper;
import com.ctg.sysmgr.sso.client.control.util.LoginStatuHelper;

import net.sf.json.JSONObject;

public class RealSubmitFilter extends AbstractCasFilter{
	
	/**
     * The URL to the CAS Server login.
     */
    private String casServerLoginUrl;
    
    private String serverName;
    
    public void init(){
		super.init();
		
		CommonUtils.assertNotNull(this.casServerLoginUrl, "casServerLoginUrl cannot be null.");
		CommonUtils.assertNotNull(this.serverName, "serverName cannot be null.");
	}
    
    protected void initInternal(final FilterConfig filterConfig) throws ServletException {
        if (!isIgnoreInitConfiguration()) {
            super.initInternal(filterConfig);
            setCasServerLoginUrl(getPropertyFromInitParams(filterConfig, "casServerLoginUrl", null));
            setServerName1(getPropertyFromInitParams(filterConfig, "serverName", null));
        }
	}

	public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain)
			throws IOException, ServletException {
		
		HttpServletRequest request = (HttpServletRequest)servletRequest;
		HttpServletResponse response = (HttpServletResponse) servletResponse;
		final DefaultHttpClient httpClient = HttpClientHelper.getHttpClient();
		
		JSONObject ltJson = getLoginTicket(request, response, httpClient);
		
		if (ltJson == null) {
			httpClient.getConnectionManager().shutdown();
			LoginStatuHelper.sendLoginStatu(response, request.getContextPath()+"/rlogin", "9001", "get login ticket failed.");
			return;
		}
		
		boolean isSuccess = realSubmit(request, response, httpClient, ltJson);
		
		if (!isSuccess) {
			httpClient.getConnectionManager().shutdown();
			LoginStatuHelper.sendLoginStatu(response, request.getContextPath()+"/rlogin", "9002", "login failed.");
			return;
		}
		
        httpClient.getConnectionManager().shutdown();
		
	}
	
	private boolean realSubmit(HttpServletRequest request, HttpServletResponse response, DefaultHttpClient httpClient, JSONObject ltJson){
		HttpPost httpPost = new HttpPost(this.casServerLoginUrl);
		String userAgentHeader = request.getHeaders("user-agent").nextElement();
		httpPost.addHeader("user-agent", userAgentHeader);
		
		boolean isSuccess = false;
		try{
			List<NameValuePair> nvps = new ArrayList<NameValuePair>();  
	        nvps.add(new BasicNameValuePair("username", request.getParameter("username")));  
	        nvps.add(new BasicNameValuePair("password", request.getParameter("password")));  
	        nvps.add(new BasicNameValuePair("execution", ltJson.getString("execution")));  
	        nvps.add(new BasicNameValuePair("lt", ltJson.getString("lt")));  
	        nvps.add(new BasicNameValuePair("_eventId", "submit"));
	        
	        httpPost.setEntity(new UrlEncodedFormEntity(nvps));  
	        
	        //final DefaultHttpClient httpClient = HttpClientHelper.getHttpClient();
	        HttpResponse httpResponse = httpClient.execute(httpPost);

	        HttpSession session =  request.getSession(true);
	        session.setAttribute("cookieStore", httpClient.getCookieStore());
	        
	        HttpEntity entity = httpResponse.getEntity();
	        
	        if (entity != null) {
				String result = EntityUtils.toString(entity,"utf-8");
				if (result != null && !result.equals("")){
					sendErrorMsg(result, response);
				}else {
					redirectSuccess(httpResponse, response);
				}
			}
	        
	        isSuccess = true;
		}catch(Exception e) {
			e.printStackTrace();
		}
		
		return isSuccess;
	}
	
	/**
	 * 获取登录票据
	 * @param request
	 * @param response
	 * @return
	 * @throws Exception
	 */
	private JSONObject getLoginTicket(HttpServletRequest request, HttpServletResponse response, DefaultHttpClient httpClient) {
		
		HttpGet httpGet = new HttpGet(buildGetLTUrl(request));
		String userAgentHeader = request.getHeaders("user-agent").nextElement();
		httpGet.setHeader("user-agent", userAgentHeader);
		
		HttpResponse httpResponse = null;
		try {
			httpResponse = httpClient.execute(httpGet);
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		if (httpResponse == null) {
			return null;
		}
		
		if (httpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
			HttpEntity entity = httpResponse.getEntity();
			
			return paraseLoginTicket(entity);
		}
		
		return null;
	}
	
	/**
	 * 解析登陆票据
	 * @param entity
	 * @return
	 * @throws Exception
	 */
	private JSONObject paraseLoginTicket(HttpEntity entity) {
		
		if (entity == null) {
			return null;
		}
		
		String result = null;
		try {
			result = EntityUtils.toString(entity,"utf-8");
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		if (result == null) {
			return null;
		}
		
		try{
			return JSONObject.fromObject(result);
		}catch(Exception e) {
			return null;
		}
		
		
	}
	
	/**
	 * 组装获取login ticket的url
	 * @param request
	 * @return
	 */
	private String buildGetLTUrl(HttpServletRequest request){
		StringBuffer sb = new StringBuffer();
		sb.append(this.casServerLoginUrl);
		sb.append("?mode=rlogin&TARGET=");
		sb.append(this.serverName);
		sb.append(request.getContextPath());
		sb.append("/rlogin");
		
		return sb.toString();
	}
	
	/**
	 * 登陆失败把失败原因输出到前端
	 * @param result
	 * @param response
	 */
	private void sendErrorMsg(String result, HttpServletResponse response) {
		response.setContentType("text/html;charset=UTF-8");
		try{
			PrintWriter out = response.getWriter();
	        out.print(result);
	        out.flush();
	        out.close();
	    }catch(Exception e){
	    	e.printStackTrace();
	    }
	}
	
	/**
	 * 登陆成功后重定向
	 * @param httpResponse
	 * @param response
	 */
	private void redirectSuccess(HttpResponse httpResponse, HttpServletResponse response){
		String location = getLocation(httpResponse);
		
		try{
			response.sendRedirect(location);
		}catch(Exception e) {
			e.printStackTrace();
		}
		
	}
	
	/**
	 * 获取重定向url
	 * @param httpResponse
	 * @return
	 */
	private String getLocation(HttpResponse httpResponse){
		Header[] h = httpResponse.getAllHeaders();
		for (Header hd : h){
			if (hd.getName().equals("Location")){
				return hd.getValue();
			}
		}
		
		return null; 
	}
	
	/**
	 * set server login url
	 * @param casServerLoginUrl
	 */
	public final void setCasServerLoginUrl(final String casServerLoginUrl) {
        this.casServerLoginUrl = casServerLoginUrl;
    }

	/**
	 * set serverName
	 * @param serverName
	 */
	public final void setServerName1(final String serverName) {
        if (serverName != null && serverName.endsWith("/")) {
            this.serverName = serverName.substring(0, serverName.length() - 1);
            logger.info("Eliminated extra slash from serverName [{}].  It is now [{}]", serverName, this.serverName);
        } else {
            this.serverName = serverName;
        }
    }
}
